use crate::global;
use core_api::db;
use futures_util::TryStreamExt;
use reqwest;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, path::Path};
use tauri::{command, AppHandle, Runtime};
use tauri_plugin_shell::ShellExt;
use tokio::{
    fs::File,
    io::{AsyncWriteExt, BufWriter},
};
const ZIP: &str = "7z";

type Result<T> = std::result::Result<T, String>;

async fn download_one<R: Runtime>(
    _app: &AppHandle<R>,
    key: &String,
    url: &str,
    file_path: &Path,
    headers: &HashMap<String, String>,
    //on_progress: &Channel<DownloadStatus>,
) -> Result<()> {
    // let client = reqwest::Client::new();
    let client = reqwest::Client::builder()
        // 连接建立超时（TCP handshake）,默认 connect_timeout = None （即不限制，直到 OS socket 层报错为止）
        .connect_timeout(std::time::Duration::from_secs(30))
        // 整个请求的超时时间（包括连接、读写）,默认 timeout = None （即无限制，可能会一直卡住，直到服务器或网络层断开）
        .timeout(std::time::Duration::from_secs(60))
        .build()
        .map_err(|e| {
            log::error!("下载文件出错0:{:?}", e,);
            "下载文件出错0".to_string()
        })?;

    let mut request: reqwest::RequestBuilder = client.get(url);

    for (key, value) in headers {
        request = request.header(key, value);
    }

    let response = request
        .send()
        .await
        .map_err(|_| "下载文件出错1!".to_string())?;

    if !response.status().is_success() {
        return Err(format!(
            "code:{},msg:{}",
            response.status().as_u16(),
            response.text().await.unwrap_or_default(),
        ));
    }
    let total = response.content_length().unwrap_or(0);

    let mut file = BufWriter::new(File::create(file_path).await.map_err(|e| {
        log::error!("创建文件错误2:{:?},file={:?}", e, &file_path);
        "创建文件错误2!".to_string()
    })?);
    let mut stream = response.bytes_stream();

    let mut pre_pecent = 0u8; //之前的进度百分比
    let mut sum_bytes = 0; //下载的总字节数

    while let Some(chunk) = stream
        .try_next()
        .await
        .map_err(|_| "下载文件出错3!".to_string())?
    {
        file.write_all(&chunk)
            .await
            .map_err(|_| "下载文件出错4!".to_string())?;

        sum_bytes += chunk.len();
        let current_pecent = ((sum_bytes as f64 / total as f64) * 100.0) as u8;
        if current_pecent > pre_pecent {
            let _ = global::read()
                .get_message_manager()
                .send_msg(db::Message::new(
                    db::MsgFlag::DOWNLOAD,
                    db::MsgStatus::PROGRESS,
                    key.clone(),
                    current_pecent.to_string(),
                ));
        }
        pre_pecent = current_pecent;
    }
    file.flush()
        .await
        .map_err(|_| "下载文件出错5!".to_string())?;

    Ok(())
}

#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DownloadArgsFile {
    key: String,
    save_name: String,
    save_path: String,
    url: String,
}

#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DownloadArgs {
    // package_name: String,
    files: Vec<DownloadArgsFile>,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DownloadStatus {
    key: String,
    status: String,
    percent: u8,
}

/// 复杂参数需要实现 Clone, Serialize, Deserialize
#[command]
pub async fn download_package<R: Runtime>(
    app: AppHandle<R>,
    args: DownloadArgs,
    headers: HashMap<String, String>,
    // on_progress: Channel<DownloadStatus>,
) -> Result<()> {
    //println!("args: {:?} , headers:{:?}", args, &headers);
    // 保存的目录 ,没有则创建
    // let dest_path = Path::new(&args.save_path);
    // if !dest_path.exists() {
    //     let _ = std::fs::create_dir_all(dest_path);
    // }

    // let package_name = args.package_name;
    for file in args.files.iter() {
        let save_path = Path::new(&file.save_path);
        if !save_path.exists() {
            let _ = std::fs::create_dir_all(save_path);
        }

        // 下载
        match download_one(
            &app,
            &file.key,
            &file.url,
            save_path.join(&file.save_name).as_path(),
            &headers,
        )
        .await
        {
            Err(e) => {
                let _ = global::read()
                    .get_message_manager()
                    .send_msg(db::Message::new(
                        db::MsgFlag::DOWNLOAD,
                        db::MsgStatus::ERROR,
                        file.key.clone(),
                        e.to_string(),
                    ));

                continue;
            }

            Ok(()) => {
                // 打包
                // package(
                //     &app,
                //     (dest_path.clone() + &package_name + ".7z").as_str(),
                //     (dest_path.clone() + &file.name).as_str(),
                // )
                // .await?;
                // let _ = &on_progress.send(DownloadStatus {
                //     file_index,
                //     status: "完成".to_string(),
                //     percent: 100,
                // });

                // let _ = app.emit(
                //     EVENT_DOWNLOAD,
                //     DownloadStatus {
                //         key: file.key.clone(),
                //         status: "完成".to_string(),
                //         percent: 100,
                //     },
                // );
                // global::write().add_status(file.key.clone(), 100);

                let _ = global::read()
                    .get_message_manager()
                    .send_msg(db::Message::new(
                        db::MsgFlag::DOWNLOAD,
                        db::MsgStatus::SUCCESS,
                        file.key.clone(),
                        100.to_string(),
                    ));
            }
        }
    }

    Ok(())
}

/// 打包文件
pub async fn _package<R: Runtime>(
    app: &AppHandle<R>,
    zip_path: &str,
    file_path: &str,
) -> Result<()> {
    let cmd = app.shell().sidecar(ZIP).unwrap().args(&[
        "a", "-mx=0", "-mhe=on", "-bd", "-aoa", "-sdel", "-p123", zip_path, file_path,
    ]);

    let cmd_run = cmd.output().await;
    if let Ok(output) = cmd_run {
        println!("zip success!!!,{},{}", zip_path, output.status.success());
    }
    Ok(())
}

#[command]
pub async fn unpackage<R: Runtime>(
    app: AppHandle<R>,
    zip_path: &str,
    dest_path: &Path,
    password: &str,
) -> Result<bool> {
    // 确保解压目录存在
    if !dest_path.exists() {
        let _ = std::fs::create_dir_all(dest_path);
    }
    // "C:\Program Files\7-Zip\7z.exe" x -aoa -p123 -od:/a/to  b.zip
    let cmd = app.shell().sidecar(ZIP).unwrap().args(&[
        "x",
        "-aoa", //覆盖
        (String::from("-p") + password).as_str(),
        (String::from("-o") + dest_path.as_os_str().to_str().unwrap()).as_str(),
        zip_path,
    ]);

    let cmd_run = cmd.output().await;
    match cmd_run {
        Ok(output) => {
            // println!("unzip success!!!,{},{}", zip_path, output.status.success());
            // let err_bytes = output.stderr;
            // let err = String::from_utf8_lossy(&err_bytes);
            // println!("uzip:{}", err);
            Ok(output.status.success())
        }
        Err(err) => Err(err.to_string()),
    }
}

use futures_util::StreamExt;
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
use std::io::Write;
use tauri_plugin_dialog::DialogExt;
#[tauri::command]
pub async fn download_file(
    app: tauri::AppHandle,
    url: String,
    save_name: String,
    headers: HashMap<String, String>,
) -> Result<String> {
    // 弹出保存对话框
    let path = app
        .dialog()
        .file()
        .set_file_name(&save_name)
        .blocking_save_file();

    let Some(file_path) = path else {
        return Err("用户取消保存".into());
    };

    // 转换成 PathBuf
    let path_buf = file_path.as_path().unwrap();

    // 创建文件
    let mut file = std::fs::File::create(&path_buf).map_err(|e| {
        let msg = format!("下载错误 0:{:?}", e);
        log::error!("{}", &msg);
        msg
    })?;

    // 构建 HeaderMap
    let mut header_map = HeaderMap::new();

    for (k, v) in headers {
        let lower = k.to_ascii_lowercase();
        let name = HeaderName::try_from(lower.as_str()).map_err(|e| {
            let msg = format!("下载错误 1:{:?}", e);
            log::error!("{}", &msg);
            msg
        })?;
        let value = HeaderValue::try_from(v.as_str()).map_err(|e| {
            let msg = format!("下载错误 2:{:?}", e);
            log::error!("{}", &msg);
            msg
        })?;
        header_map.insert(name, value);
    }

    let client = reqwest::Client::new();
    let response = client
        .get(&url)
        .headers(header_map)
        .send()
        .await
        .map_err(|e| {
            let msg = format!("下载错误 3:{:?}", e);
            log::error!("{}", &msg);
            msg
        })?;

    let mut stream = response.bytes_stream();

    while let Some(chunk) = stream.next().await {
        let chunk = chunk.map_err(|e| {
            let msg = format!("下载错误 4:{:?}", e);
            log::error!("{}", &msg);
            msg
        })?;
        file.write_all(&chunk).map_err(|e| {
            let msg = format!("下载错误 5:{:?}", e);
            log::error!("{}", &msg);
            msg
        })?;
    }

    Ok(path_buf.to_string_lossy().to_string())
}
